﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

/// <summary>
/// 包含 在此部队中的士兵
/// 执行一些部队行为  列如 1.分散成一条直线打城墙 2.圆形包围某个点  3.扇形包围某个点  4.扩散
/// </summary>
public class EntitySTroop : BattleEntity
{
    List<SoldierVo> m_lisVo;
    private int m_iSoliderNum;
    private int m_iSoliderId;
    private string m_strModelPath;
    List<EntitySolider> m_lisSolider;
    private Vector3 m_v3TroopBornPos;
    private bool m_bLeft;
    private int m_iIndex;
    private NStateMachine<EntitySTroop> m_pStateMachine;
    private GameObject m_pGameObj;

    //--状态机用到的一些临时变量
    public float m_fLastSearchT = 0;
    public float m_fSearchCD = 0.1f;
    public float m_fLockRange = 8;
    public EntitySTroop m_pAttackTag;

    public bool bLeft
    {
        get { return m_bLeft; }
    }

    public override void OnCreate(params object[] args)
    {
        m_lisVo = (List<SoldierVo>)args[0];
        m_v3TroopBornPos = (Vector3)args[1];
        m_bLeft = (bool)args[2];
        m_iIndex = (int)args[3];

        m_pGameObj = new GameObject();
        m_pGameObj.name = "Troop_" + m_iIndex.ToString();
        m_pGameObj.transform.position = Vector3.zero;
        m_pGameObj.transform.localEulerAngles = Vector3.zero;
        m_pGameObj.transform.localScale = Vector3.one;

        m_iSoliderNum = 12;
        m_iSoliderId = 100;
        m_strModelPath = "Battle/Troop/batman/Prefab/batman_3D";
        CreateSolider();
        Dictionary<string,NState<EntitySTroop>> states = new Dictionary<string, NState<EntitySTroop>>()
        {
            { STroopStateDef.Default,STroopStateDef.s_stateDefault},
            { STroopStateDef.ForwardSearch,STroopStateDef.s_stateForwardSearch},
            { STroopStateDef.Attack,STroopStateDef.s_stateAttack},
            { STroopStateDef.Dead,STroopStateDef.s_stateDead},
        };
        m_pStateMachine = new NStateMachine<EntitySTroop>(this, states, STroopStateDef.Default);
        m_pStateMachine.ChangeState(STroopStateDef.Default);
    }

    public override void OnUpdate(float deltaTime)
    {
        base.OnUpdate(deltaTime);
        m_pStateMachine.OnUpdate();
    }

    public void ChangeState(string state, params object[] args)
    {
        m_pStateMachine.ChangeState(state, args);
    }

    private void CreateSolider()
    {
        for (int i = 0; i < m_lisVo.Count; i++)
        {
            for (int j = 0; j < m_iSoliderNum; j++)
            {
                EntitySolider solider = BattleEntityFactory.Instance.CreateBtEntity<EntitySolider>() as EntitySolider;
                solider.SetParent(this);
                solider.OnCreate(m_iSoliderId,m_strModelPath,m_bLeft,j);
                InsertChild(solider.Id);
            }
        }
        RestFormation();
    }
    //布置小队的阵型
    public void RestFormation()
    {
        List<EntitySolider> child = GetAllChild(true);

        int lie = 3;
        int hang = 4;
        int lieKuang = 1;
        int hangKuang = 1;
        for (int i = 0; i < hang; i++)
        {
            for (int j = 0; j < lie; j++)
            {
                int index = j + i * lie;
                if(index < child.Count)
                {
                    Vector3 pos = m_v3TroopBornPos + new Vector3(hangKuang * i, 0, lieKuang * j);
                    child[index].m_pGameObj.transform.position = pos;
                }
            }
        }
    }

    private List<EntitySolider> GetAllChild(bool fresh = false)
    {
        if (fresh || m_lisSolider == null)
        {
            m_lisSolider = m_lisChild.ConvertAll<EntitySolider>(s => (EntitySolider)s);
        }
        return m_lisSolider;
    }

    public List<EntitySolider> GetAliveChild()
    {
        List<EntitySolider> result = new List<EntitySolider>();
        List<EntitySolider> allChild = GetAllChild();
        for (int i = 0; i < allChild.Count; i++)
        {
            if (allChild[i].Alive)
            {
                result.Add(allChild[i]);
            }
        }
        return result;
    }

    public Vector3 GetTroopCenter()
    {
        List<EntitySolider> childs = GetAliveChild();
        Vector3 result = Vector3.zero;

        for (int i = 0; i < childs.Count; i++)
        {
            result += childs[i].m_pGameObj.transform.position;
        }
        result = result / childs.Count;
        return result;
    }

    public void CloseAliveSteer()
    {
        List<EntitySolider> alive = GetAliveChild();
        for (int i = 0; i < alive.Count; i++)
        {
            alive[i].Veh.CloseAllSteer();
        }
    }

    /// <summary>
    /// 排成一排 ZX 平面
    /// </summary>
    /// <param name="result">返回结果</param>
    /// <param name="c">直线的中点</param>
    /// <param name="dir">直线的方向</param>
    /// <param name="l">直线的长度</param>
    /// <param name="num">直线切分成几个点</param>
    /// <param name="y">直线的Y</param>
    private void GetLinePoint(List<Vector3> result,Vector3 c,Vector3 dir,float l,float num,float y)
    {
        if (num <= 1)
        {
            Debug.Log("不能把线段分成1分");
            return;
        }

        if (result == null)
            result = new List<Vector3>();
        result.Clear();

        c.y = y;
        dir.y = 0;
        //分奇偶来算
        float sl = l / (num - 1);
        for (int i = 0; i < num; i++)
        {
            bool odd = i % 2 != 0;
            float dirL = 0;
            if (num % 2 != 0)
            {
                //奇数 An =  (n + 1)/2 取整 * l * 正负1
                dirL = Mathf.FloorToInt((i + 1) / 2) * sl;
            }
            else
            {
                //偶数 An = 0.5*l*正负1 + n/2取整 * 1 * 正负1
                dirL = Mathf.FloorToInt(i / 2) * sl + 0.5f * sl;
            }
            result.Add(c + dir * (odd ? -1 : 1)*dirL);
        }
    }

    public void LineSearch(Vector3 center,Vector3 dir)
    {
        List<Vector3> point = new List<Vector3>();
        List<EntitySolider> childs = GetAliveChild();
        GetLinePoint(point, center, dir, childs.Count, childs.Count, 0);
        for (int i = 0; i < childs.Count; i++)
        {
            int index = i;
            if(i < point.Count)
            {
                childs[i].Go(point[i],(steer)=> 
                {
                    if(steer.CName == SteerName.StN_SteerForPoint)
                    {
                        Debug.Log(steer.gameObject.name);
                        childs[index].PlayClip("batman@a1", true);
                    }
                });
            }
            else
            {
                childs[i].Go(point[0],null);
            }
        }


    }

    /// <summary>
    /// 扇形包围 ZX平面  最好做到不要围成一个圈
    /// </summary>
    /// <param name="result">返回结果</param>
    /// <param name="c">扇形的中心点</param>
    /// <param name="dir">扇形的中心线方向</param>
    /// <param name="r">扇形的边长</param>
    /// <param name="angle">扇形的角度</param>
    /// <param name="num">切分成几个点</param>
    /// <param name="y">指定的Y</param>
    public void GetRoundPoint(List<Vector3> result,Vector3 c, Vector3 dir,float r,int angle,int num,float y)
    {
        if (result == null)
            result = new List<Vector3>();
        result.Clear();

        Vector3 pDir = Quaternion.AngleAxis(90, Vector3.up) * dir;
        pDir = c + pDir.normalized * r;
        Debug.LogFormat("{0}  {1}", c, pDir);

        c.y = y;
        dir.y = 0;
        //分奇偶来算
        int sAngle = angle / (num - 1);
        for (int i = 0; i < num; i++)
        {
            bool odd = i % 2 != 0;
            Vector3 tDir = dir;
            int btAngle = 0;
            if (num % 2 != 0)
            {
                //奇数 An =  (n + 1)/2 取整 * l * 正负1
                btAngle = Mathf.FloorToInt((i + 1) / 2) * sAngle;
            }
            else
            {
                //偶数 An = 0.5*l*正负1 + n/2取整 * 1 * 正负1
                btAngle = (int)(Mathf.FloorToInt(i / 2) * sAngle + 0.5f * sAngle);
            }
            tDir = Quaternion.AngleAxis(btAngle * (odd ? -1:1) , Vector3.up) * dir;
            result.Add(c + tDir.normalized * r);
        }
    }

    public void RoundSearch(Vector3 c,Vector3 dir,float r,int angle,Action<EntitySolider> onArrival, bool collision)
    {
        List<Vector3> point = new List<Vector3>();
        List<EntitySolider> childs = GetAliveChild();
        GetRoundPoint(point, c, dir, r, angle,childs.Count, 0);
        for (int i = 0; i < childs.Count; i++)
        {
            int index = i;
            if (i < point.Count)
            {
                childs[i].Go(point[i], (steer) =>
                {
                    if (steer.CName == SteerName.StN_SteerForPoint)
                    {
                        //Debug.Log(steer.gameObject.name);
                        childs[index].PlayClip("batman@a1", true);
                        childs[index].Veh.SetSteerState(SteerName.StN_SteerSeparation, collision);
                        if (onArrival != null)
                        {
                            onArrival(childs[index]);
                        }
                    }
                });
            }
            else
            {
                childs[i].Go(point[0],(steer)=> 
                {
                    if(steer.CName == SteerName.StN_SteerForPoint)
                    {
                        Debug.Log(steer.gameObject.name);
                    }
                },collision);
            }
        }
    }

}